﻿using System.Collections;

namespace LaoLuo
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Text;

    /// <summary>
    /// 定义一个区间
    /// </summary>
    /// <typeparam name="T">区间的值的类型</typeparam>
    public struct Interval<T> : IEnumerable<T> where T : IComparable<T>
    {
        /// <summary>
        /// 开始端点
        /// </summary>
        private readonly Point<T> _endPoint;

        /// <summary>
        /// 结束端点
        /// </summary>
        private readonly Point<T> _beginPoint;

        /// <summary>
        /// 值的类型
        /// </summary>
        private Type _t;

        ////private Func<T, T, bool> _greaterThanOrEqual;
        ////private Func<T, T, bool> _lessThanOrEqual;
        ////private Func<T, T, bool> _greaterThan;
        ////private Func<T, T, bool> _lessThan;

        /// <summary>
        /// 初始化一个实例
        /// </summary>
        /// <param name="beginPoint">开始端点</param>
        /// <param name="endPoint">结束端点</param>
        private Interval(Point<T> beginPoint, Point<T> endPoint)
        {
            this._beginPoint = beginPoint;
            this._endPoint = endPoint;
            this._t = typeof(T);

            var paramBegin = Expression.Parameter(this._t, "begin");
            var paramEnd = Expression.Parameter(this._t, "end");
            var paramTest = Expression.Parameter(this._t, "value");

            ////this._greaterThanOrEqual = Expression.Lambda<Func<T, T, bool>>(Expression.GreaterThanOrEqual(paramTest, paramBegin), paramTest, paramBegin).Compile();
            ////this._lessThanOrEqual = Expression.Lambda<Func<T, T, bool>>(Expression.LessThanOrEqual(paramTest, paramEnd), paramTest, paramEnd).Compile();
            ////this._greaterThan = Expression.Lambda<Func<T, T, bool>>(Expression.GreaterThan(paramTest, paramBegin), paramTest, paramBegin).Compile();
            ////this._lessThan = Expression.Lambda<Func<T, T, bool>>(Expression.LessThan(paramTest, paramEnd), paramTest, paramEnd).Compile();
        }

        /// <summary>
        /// 点在区间中的开闭性
        /// </summary>
        public enum PointType
        {
            /// <summary>
            /// 点在区间中开
            /// </summary>
            Open,

            /// <summary>
            /// 点在区间中闭
            /// </summary>
            Closed
        }

        /// <summary>
        /// 获取开始端点
        /// </summary>
        public T BeginPoint
        {
            get { return _beginPoint.Value; }
        }

        /// <summary>
        /// 获取结束端点
        /// </summary>
        public T EndPoint
        {
            get { return _endPoint.Value; }
        } 

        /// <summary>
        /// 初始化一个开区间
        /// </summary>
        /// <param name="beginPoint">区间的开始端点</param>
        /// <param name="endPoint">区间的结束端点</param>
        /// <returns>拥有指定端点的开区间</returns>
        public static Interval<T> NewOpenInterval(T beginPoint, T endPoint)
        {
            return new Interval<T>(Point<T>.NewOpenPoint(beginPoint), Point<T>.NewOpenPoint(endPoint));
        }

        /// <summary>
        /// 初始化一个闭区间
        /// </summary>
        /// <param name="beginPoint">区间的开始端点</param>
        /// <param name="endPoint">区间的结束端点</param>
        /// <returns>拥有指定端点的闭区间</returns>
        public static Interval<T> NewClosedInterval(T beginPoint, T endPoint)
        {
            return new Interval<T>(Point<T>.NewClosedPoint(beginPoint), Point<T>.NewClosedPoint(endPoint));
        }

        /// <summary>
        /// 初始化一个半开半闭区间
        /// </summary>
        /// <param name="beginPoint">区间的开始端点</param>
        /// <param name="endPoint">区间的结束端点</param>
        /// <returns>拥有指定端点的开区间</returns>
        public static Interval<T> NewLeftOpenRightClosedInterval(T beginPoint, T endPoint)
        {
            return new Interval<T>(Point<T>.NewOpenPoint(beginPoint), Point<T>.NewClosedPoint(endPoint));
        }

        /// <summary>
        /// 初始化一个半开半闭区间
        /// </summary>
        /// <param name="beginPoint">区间的开始端点</param>
        /// <param name="endPoint">区间的结束端点</param>
        /// <returns>拥有指定端点的半开半闭区间</returns>
        public static Interval<T> NewLeftClosedRightOpenInterval(T beginPoint, T endPoint)
        {
            return new Interval<T>(Point<T>.NewClosedPoint(beginPoint), Point<T>.NewOpenPoint(endPoint));
        }

        /// <summary>
        /// 获取区间是否包含点
        /// </summary>
        /// <param name="pointValue">要判断的点</param>
        /// <returns>如果区间包含点, 返回true, 否则返回false</returns>
        public bool HasPoint(T pointValue)
        {
            ////var g = this._beginPoint.PointType == PointType.Open ? this._greaterThan(pointValue, this._beginPoint.Value) : this._greaterThanOrEqual(pointValue, this._beginPoint.Value);

            ////var l = this._endPoint.PointType == PointType.Open ? this._lessThan(pointValue, this._endPoint.Value) : this._lessThanOrEqual(pointValue, this._endPoint.Value);

            ////return g && l;

            var g = this._beginPoint.PointType == PointType.Open ? pointValue.CompareTo(this._beginPoint.Value) > 0 : pointValue.CompareTo(this._beginPoint.Value) >= 0;

            var l = this._endPoint.PointType == PointType.Open ? pointValue.CompareTo(this._endPoint.Value) < 0 : pointValue.CompareTo(this._endPoint.Value) <= 0;

            return g && l;
        }

        /// <summary>
        /// 定义一个区间中的点
        /// </summary>
        /// <typeparam name="TValue">点的类型</typeparam>
        public struct Point<TValue>
            where TValue : IComparable<TValue>
        {
            /// <summary>
            /// 点的值
            /// </summary>
            private readonly TValue _value;

            /// <summary>
            /// 点的开闭性
            /// </summary>
            private readonly PointType _pointType;

            /// <summary>
            /// 初始化一个实例
            /// </summary>
            /// <param name="value">点的值</param>
            /// <param name="pointType">点在区间中的开闭性</param>
            private Point(TValue value, PointType pointType)
            {
                this._value = value;
                this._pointType = pointType;
            }

            /// <summary>
            /// 获取点的类型
            /// </summary>
            public PointType PointType
            {
                get { return this._pointType; }
            }

            /// <summary>
            /// 获取点的值
            /// </summary>
            public TValue Value
            {
                get { return _value; }
            }

            /// <summary>
            /// 初始化一个空心点
            /// </summary>
            /// <param name="value">点的值</param>
            /// <returns>拥有指定值的空心点</returns>
            public static Point<TValue> NewOpenPoint(TValue value)
            {
                return new Point<TValue>(value, PointType.Open);
            }

            /// <summary>
            /// 初始化一个实心点的
            /// </summary>
            /// <param name="value">点的值</param>
            /// <returns>拥有指定值的实心点</returns>
            public static Point<TValue> NewClosedPoint(TValue value)
            {
                return new Point<TValue>(value, PointType.Closed);
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            yield return this.BeginPoint;
            yield return this.EndPoint;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}
